// Created by plusminus on 20:50:06 - 03.10.2008
package org.andnav.osm.views.overlay;

import java.util.ArrayList;
import java.util.List;

//import org.andnav.osm.R;
import com.robert.maps.R;
import org.andnav.osm.views.OpenStreetMapView;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;


public class OpenStreetMapViewItemizedOverlayWithFocus<T extends OpenStreetMapViewOverlayItem> extends OpenStreetMapViewItemizedOverlay<T> {
	// ===========================================================
	// Constants
	// ===========================================================
	
	public static final int DESCRIPTION_BOX_PADDING = 5; //3
	public static final int DESCRIPTION_BOX_CORNERWIDTH = 2; //3
	
	public static final int DESCRIPTION_LINE_HEIGHT = 12;
	/** Additional to <code>DESCRIPTION_LINE_HEIGHT</code>. */
	public static final int DESCRIPTION_TITLE_EXTRA_LINE_HEIGHT = 2;
	

	//joeng
	//protected static final Point DEFAULTMARKER_FOCUSED_HOTSPOT = new Point(10, 19);
	protected static final Point DEFAULTMARKER_FOCUSED_HOTSPOT = new Point(13, 19);
	//joeng
	//protected static final int DEFAULTMARKER_BACKGROUNDCOLOR = Color.rgb(101, 185, 74);
	protected static final int DEFAULTMARKER_BACKGROUNDCOLOR = Color.rgb(224, 224, 224);
	
	protected static final int DESCRIPTION_MAXWIDTH = 200;

	// ===========================================================
	// Fields
	// ===========================================================
	
	protected final Point mMarkerFocusedHotSpot; 
	protected final Drawable mMarkerFocusedBase;
	protected final int mMarkerFocusedBackgroundColor;
	protected final int mMarkerFocusedWidth, mMarkerFocusedHeight; 
	protected final Paint mMarkerBackgroundPaint, mDescriptionPaint, mTitlePaint;
	
	protected int mFocusedItemIndex;
	protected boolean mFocusItemsOnTap;
	private Point mFocusedScreenCoords = new Point();
	
	private final String UNKNOWN;

	// ===========================================================
	// Constructors
	// ===========================================================
	
	public OpenStreetMapViewItemizedOverlayWithFocus(final Context ctx, final List<T> aList, final OnItemTapListener<T> aOnItemTapListener) {
		this(ctx, aList, null, null, null, null, NOT_SET, aOnItemTapListener, null);
	}
	//joeng
	public OpenStreetMapViewItemizedOverlayWithFocus(final Context ctx, final List<T> aList, 
			final OnItemTapListener<T> aOnItemTapListener,final OnItemLongPressListener<T> aOnItemLongPressListener) {
		this(ctx, aList, null, null, null, null, NOT_SET, aOnItemTapListener, aOnItemLongPressListener);
	}
	//joeng
	public OpenStreetMapViewItemizedOverlayWithFocus(final Context ctx, final List<T> aList, final Drawable pMarker, 
			final Point pMarkerHotspot, final Drawable pMarkerFocusedBase, final Point pMarkerFocusedHotSpot, 
			final int pFocusedBackgroundColor, final OnItemTapListener<T> aOnItemTapListener) {
		this(ctx, aList, pMarker, pMarkerHotspot, pMarkerFocusedBase, pMarkerFocusedHotSpot, pFocusedBackgroundColor, aOnItemTapListener, null);
	}
	//joeng
	public OpenStreetMapViewItemizedOverlayWithFocus(final Context ctx, final List<T> aList, final Drawable pMarker, 
			final Point pMarkerHotspot, final Drawable pMarkerFocusedBase, final Point pMarkerFocusedHotSpot, 
			final int pFocusedBackgroundColor, final OnItemTapListener<T> aOnItemTapListener,
			final OnItemLongPressListener<T> aOnItemLongPressListener) {
		super(ctx, aList, pMarkerFocusedBase, pMarkerHotspot, aOnItemTapListener, aOnItemLongPressListener);
		
		UNKNOWN = ctx.getString(R.string.unknown);
		
		this.mMarkerFocusedBase = (pMarkerFocusedBase != null) ? pMarkerFocusedBase : ctx.getResources().getDrawable(R.drawable.marker_default_focused_base);
		
		this.mMarkerFocusedHotSpot = (pMarkerFocusedHotSpot != null) ? pMarkerFocusedHotSpot : DEFAULTMARKER_FOCUSED_HOTSPOT;
		
		if(pFocusedBackgroundColor != NOT_SET)
			this.mMarkerFocusedBackgroundColor = pFocusedBackgroundColor;
		else
			this.mMarkerFocusedBackgroundColor = DEFAULTMARKER_BACKGROUNDCOLOR;
		
		this.mMarkerBackgroundPaint = new Paint(); // Color is set in onDraw(...)
		
		this.mDescriptionPaint = new Paint();
		this.mDescriptionPaint.setAntiAlias(true);
		this.mTitlePaint = new Paint();
		this.mTitlePaint.setFakeBoldText(true);
		this.mTitlePaint.setAntiAlias(true);

		this.mMarkerFocusedWidth = this.mMarkerFocusedBase.getIntrinsicWidth();
		this.mMarkerFocusedHeight = this.mMarkerFocusedBase.getIntrinsicHeight();
	}

	// ===========================================================
	// Getter & Setter
	// ===========================================================
	
	public void setFocusedItem(final int pIndex){
		this.mFocusedItemIndex = pIndex;
	}
	
	public void unSetFocusedItem(){
		this.mFocusedItemIndex = NOT_SET;
	}
	
	public void setFocusedItem(final T pItem){
		final int indexFound = super.mItemList.indexOf(pItem);
		if(indexFound < 0)
			throw new IllegalArgumentException();
		
		this.setFocusedItem(indexFound);
	}
	
	public void setFocusItemsOnTap(final boolean doit) {
		this.mFocusItemsOnTap = doit;
	}

	public void setPathPosList(ArrayList<Integer> aPathPosList) {
		super.mPathPosList = aPathPosList;
	}

	// ===========================================================
	// Methods from SuperClass/Interfaces
	// ===========================================================
	
	@Override
	protected boolean onTap(int pIndex) {
		if(this.mFocusItemsOnTap)
			this.mFocusedItemIndex = pIndex;
			
		return super.onTap(pIndex);
	}
	
	//joeng
	@Override
	protected boolean onItemPress(int pIndex) {
		if(this.mFocusItemsOnTap)
			this.mFocusedItemIndex = pIndex;
			
		return super.onItemPress(pIndex);
	}
	
	@Override
	protected void onDrawFinished(Canvas c, OpenStreetMapView osmv) {
		if(this.mFocusedItemIndex != NOT_SET){
			/* Calculate and set the bounds of the marker. */
			final int left = this.mFocusedScreenCoords.x - this.mMarkerFocusedHotSpot.x;
			final int right = left + this.mMarkerFocusedWidth;
			final int top = this.mFocusedScreenCoords.y - this.mMarkerFocusedHotSpot.y;
			final int bottom = top + this.mMarkerFocusedHeight;
			this.mMarkerFocusedBase.setBounds(left, top, right, bottom);
			
			/* Strings of the OverlayItem, we need. */
			final T focusedItem = super.mItemList.get(this.mFocusedItemIndex);
			final String itemTitle = (focusedItem.mTitle == null) ? UNKNOWN : focusedItem.mTitle;
			final String itemDescription = (focusedItem.mDescription == null) ? UNKNOWN : focusedItem.mDescription;
			
			/* Store the width needed for each char in the description to a float array. This is pretty efficient. */
			final float[] widths = new float[itemDescription.length()];
			this.mDescriptionPaint.getTextWidths(itemDescription, widths);
			
			final StringBuilder sb = new StringBuilder();
			int maxWidth = 0;
			int curLineWidth = 0;
			int lastStop = 0;
			int i;
			int lastwhitespace = 0;
			/* Loop through the charwidth array and harshly insert a linebreak, 
			 * when the width gets bigger than DESCRIPTION_MAXWIDTH. */
			for (i = 0; i < widths.length; i++) {
				if(!Character.isLetter(itemDescription.charAt(i)))
					lastwhitespace = i;
				
				float charwidth = widths[i];
				       
				if(curLineWidth + charwidth> DESCRIPTION_MAXWIDTH){
					if(lastStop == lastwhitespace)
						i--;
					else
						i = lastwhitespace;
					
					
					sb.append(itemDescription.subSequence(lastStop, i));
					sb.append('\n');
					
					lastStop = i;
					maxWidth = Math.max(maxWidth, curLineWidth);
					curLineWidth = 0;
				}
				
				curLineWidth += charwidth;
			}
			/* Add the last line to the rest to the buffer. */
			if(i != lastStop){
				final String rest = itemDescription.substring(lastStop, i);
				
				maxWidth = Math.max(maxWidth, (int)this.mDescriptionPaint.measureText(rest));

				sb.append(rest);
			}
			final String[] lines = sb.toString().split("\n");
			
			/* The title also needs to be taken into consideration for the width calculation. */
			final int titleWidth = (int)this.mDescriptionPaint.measureText(itemTitle);
			
			maxWidth = Math.max(maxWidth, titleWidth);
			final int descWidth = Math.min(maxWidth, DESCRIPTION_MAXWIDTH);
			
			/* Calculate the bounds of the Description box that needs to be drawn. */
			//final int descBoxLeft = left - descWidth / 2 - DESCRIPTION_BOX_PADDING + this.mMarkerFocusedWidth / 2;
			int descBoxLeft = left - descWidth / 2 - DESCRIPTION_BOX_PADDING + this.mMarkerFocusedWidth / 2;
			//final int descBoxRight = descBoxLeft + descWidth + 2 * DESCRIPTION_BOX_PADDING;
			int descBoxRight = descBoxLeft + descWidth + 2 * DESCRIPTION_BOX_PADDING;
			int iBoxWidth=descBoxRight-descBoxLeft;
			if (iBoxWidth <this.mMarkerFocusedWidth){
				descBoxLeft = descBoxLeft - iBoxWidth / 2;
				descBoxRight = descBoxRight + iBoxWidth / 2;
			}
			final int descBoxBottom = top+3;
			final int descBoxTop = descBoxBottom 
						- DESCRIPTION_TITLE_EXTRA_LINE_HEIGHT 
						- (lines.length + 1) * DESCRIPTION_LINE_HEIGHT /* +1 because of the title. */ 
						- 2 * DESCRIPTION_BOX_PADDING;
			
			/* Twice draw a RoundRect, once in black with 1px as a small border. */
			//joeng
			//this.mMarkerBackgroundPaint.setColor(Color.BLACK);
			this.mMarkerBackgroundPaint.setColor(Color.rgb(95, 95, 95));
			//joeng
			c.save();
			c.rotate(osmv.getBearing(),this.mFocusedScreenCoords.x,this.mFocusedScreenCoords.y);
			
			//c.drawRoundRect(new RectF(descBoxLeft - 1, descBoxTop - 1, descBoxRight + 1, descBoxBottom + 1),
			c.drawRoundRect(new RectF(descBoxLeft - 2, descBoxTop - 2, descBoxRight + 2, descBoxBottom + 2),
						DESCRIPTION_BOX_CORNERWIDTH, DESCRIPTION_BOX_CORNERWIDTH,
						//this.mDescriptionPaint);
						this.mMarkerBackgroundPaint);
			this.mMarkerBackgroundPaint.setColor(this.mMarkerFocusedBackgroundColor);
			c.drawRoundRect(new RectF(descBoxLeft, descBoxTop, descBoxRight, descBoxBottom),
						DESCRIPTION_BOX_CORNERWIDTH, DESCRIPTION_BOX_CORNERWIDTH, 
						this.mMarkerBackgroundPaint);
			
			final int descLeft = descBoxLeft + DESCRIPTION_BOX_PADDING;
			int descTextLineBottom = descBoxBottom - DESCRIPTION_BOX_PADDING;
			
			/* Draw all the lines of the description. */
			for(int j = lines.length - 1; j >= 0; j--){
				c.drawText(lines[j].trim(), descLeft, descTextLineBottom, this.mDescriptionPaint);
				descTextLineBottom -= DESCRIPTION_LINE_HEIGHT;
			}
			/* Draw the title. */
			c.drawText(itemTitle, descLeft, descTextLineBottom - DESCRIPTION_TITLE_EXTRA_LINE_HEIGHT, this.mTitlePaint);
			c.drawLine(descBoxLeft, descTextLineBottom, descBoxRight, descTextLineBottom, mDescriptionPaint);
			
			/* Finally draw the marker base. This is done in the end to make it look better. */
			this.mMarkerFocusedBase.draw(c);
			c.restore();
		}
	}
	
	@Override
	protected void onDrawItem(final Canvas c, final int index, final Point screenCoords) {
		if(this.mFocusedItemIndex != NOT_SET && index == this.mFocusedItemIndex){
			/* Actual draw will take place in onDrawFinished. */
			/* Because we are reusing the screencoords apssed here, we cannot simply store the reference. */
			this.mFocusedScreenCoords.set(screenCoords.x, screenCoords.y);
		}else{
			super.onDrawItem(c, index, screenCoords);
		}
	}

	// ===========================================================
	// Methods
	// ===========================================================

	// ===========================================================
	// Inner and Anonymous Classes
	// ===========================================================
}
